package com.x2.core.util;

import cn.hutool.core.date.DateUtil;
import com.x2.core.exception.TimeMatchFormatException;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class DateUtils {
    private static String[] parsePatterns = new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy-MM"};
    public static final String DATE_FORMAT_DAY = "yyyy-MM-dd";
    public static final String DATE_FORMAT_DAY_2 = "yyyy/MM/dd";
    public static final String TIME_FORMAT_SEC = "HH:mm:ss";
    public static final String DATE_FORMAT_SEC = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_MSEC = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_FORMAT_MSEC_T = "yyyy-MM-dd'T'HH:mm:ss.SSS";
    public static final String DATE_FORMAT_MSEC_T_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    public static final String DATE_FORMAT_DAY_SIMPLE = "y/M/d";
    private static final String DATE_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$";
    private static final String DATE_REG_2 = "^[1-9]\\d{3}/(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])$";
    private static final String DATE_REG_SIMPLE_2 = "^[1-9]\\d{3}/([1-9]|1[0-2])/([1-9]|[1-2][0-9]|3[0-1])$";
    private static final String TIME_SEC_REG = "^(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$";
    private static final String DATE_TIME_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$";
    private static final String DATE_TIME_MSEC_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$";
    private static final String DATE_TIME_MSEC_T_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$";
    private static final String DATE_TIME_MSEC_T_Z_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}Z$";


    public static Timestamp nowTimestamp() {
        return new Timestamp(System.currentTimeMillis());
    }

    public static Date getSysDate() {
        return new Date();
    }


    public static String getDate() {
        return getDate("yyyy-MM-dd");
    }

    public static String getDate(String pattern) {
        return DateUtil.format(new Date(), pattern);
    }

    public static String formatDate(Date date, Object... pattern) {
        String formatDate = null;
        if (pattern != null && pattern.length > 0) {
            formatDate = DateUtil.format(date, pattern[0].toString());
        } else {
            formatDate = DateUtil.format(date, "yyyy-MM-dd");
        }

        return formatDate;
    }

    public static String formatDate2(Date date) {
        if (date == null) {
            return null;
        } else {
            return DateUtil.format(date, "yyyy-MM-dd");
        }
    }

    public static String formatTime2(Date date) {
        if (date == null) {
            return null;
        } else {
            return DateUtil.format(date, "yyyy-MM-dd HH:mm:ss");
        }
    }

    public static String getTime() {
        return formatDate(new Date(), "HH:mm:ss");
    }

    public static String getDateTime() {
        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    public static String getYear() {
        return formatDate(new Date(), "yyyy");
    }

    public static String getMonth() {
        return formatDate(new Date(), "MM");
    }

    public static String getDay() {
        return formatDate(new Date(), "dd");
    }

    public static int getDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(5);
    }

    public static String getWeek() {
        return formatDate(new Date(), "E");
    }

    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        } else {
            return DateUtil.parse(str.toString(), parsePatterns);
        }
    }

    public static long pastDays(Date date) {
        long t = (new Date()).getTime() - date.getTime();
        return t / 86400000L;
    }

    public static long subtractionDays(Date date1, Date date2) {
        long t = date1.getTime() - date2.getTime();
        return t / 86400000L;
    }

    public static long subtractionMinute(Date date1, Date date2) {
        Calendar c1 = Calendar.getInstance();
        c1.clear();
        Calendar c2 = Calendar.getInstance();
        c2.clear();
        c1.setTime(date1);
        c2.setTime(date2);
        long time1 = c1.getTimeInMillis();
        long time2 = c2.getTimeInMillis();
        long diff = time2 - time1;
        return diff / 60000L;
    }

    public static Date addOrSubtractDaysReturnDate(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(5, n);
        return calendar.getTime();
    }

    public static String addOrSubtractDaysReturnString(Date date, int n) {
        Date newDate = addOrSubtractDaysReturnDate(date, n);
        return formatDate(newDate);
    }

    public static int getDayByDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(5);
    }

    public static int getMonthByDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(2);
    }


    public static Integer[] getWeekdays(int year, int month) {
        int lastDay = getMonthDays(year, month);
        Integer[] weekdays = new Integer[lastDay];
        int firstWeekday = getWeekday(year, month);

        for (int i = 0; i < weekdays.length; ++i) {
            int temp = (firstWeekday + i) % 7;
            if (temp == 0) {
                temp = 7;
            }

            weekdays[i] = temp;
        }

        return weekdays;
    }

    public static int getMonthDays(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        return getMonthDays(calendar.getTimeInMillis());
    }

    public static int getMonthDays(Date date) {
        return getMonthDays(date.getTime());
    }

    public static int getMonthDays(long time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(time);
        int lastDay = calendar.getActualMaximum(5);
        return lastDay;
    }

    public static int getWeekday(int year, int month, int date) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, date);
        return calendar.get(7);
    }

    public static int getWeekday(int year, int month) {
        return getWeekday(year, month, 1);
    }

    public static int getWeekday(Date date) {
        return getWeekday(date.getTime());
    }

    public static int getWeekday(long time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(time);
        return calendar.get(7);
    }

    public static Integer[] getWeeks(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        int startWeek = calendar.get(3);
        calendar.set(year, month, 0);
        int endWeek = calendar.get(3);
        if (endWeek < startWeek) {
            int max = calendar.getActualMaximum(3);
            endWeek += max;
        }

        Integer[] weeks = new Integer[endWeek - startWeek + 1];

        for (int i = 0; i < weeks.length; ++i) {
            weeks[i] = startWeek + i;
        }

        return weeks;
    }

    public static Integer[] getWeeks52(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        int startWeek = calendar.get(3);
        calendar.set(year, month, 0);
        int endWeek = calendar.get(3);
        if (endWeek < startWeek) {
            int max = calendar.getActualMaximum(3);
            endWeek += max;
        }

        Integer[] weeks = new Integer[endWeek - startWeek + 1];

        for (int i = 0; i < weeks.length; ++i) {
            int temp = startWeek + i;
            if (temp <= 52) {
                weeks[i] = temp;
            }
        }

        return weeks;
    }

    public static Date[] getWeekStartAndEndDate(Date date) {
        int weekday = getWeekday(date);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(5, -1 * weekday + 1);
        Date startDate = calendar.getTime();
        calendar.add(5, 6);
        Date endDate = calendar.getTime();
        return new Date[]{startDate, endDate};
    }

    public static Date[] getWeekStartAndEndWorkDate(Date date) {
        int weekday = getWeekday(date);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(5, 2 - weekday);
        Date startDate = calendar.getTime();
        calendar.add(5, 4);
        Date endDate = calendar.getTime();
        return new Date[]{startDate, endDate};
    }

    public static Date[] getWeekStartAndEndWorkDate() {
        return getWeekStartAndEndWorkDate(new Date());
    }

    public static Date[] getWeekStartAndEndDate() {
        return getWeekStartAndEndDate(new Date());
    }

    public static int getWeekOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(3);
    }

    public static int getWeekOfYear() {
        return getWeekOfYear(new Date());
    }

    public static List<String> getBetweenDatesToString(String start, String end) {
        List<String> result = new ArrayList();

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date start_date = sdf.parse(start);
            Date end_date = sdf.parse(end);
            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(start_date);
            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(end_date);

            while (tempStart.before(tempEnd) || tempStart.equals(tempEnd)) {
                result.add(sdf.format(tempStart.getTime()));
                tempStart.add(6, 1);
            }
        } catch (ParseException var8) {
            var8.printStackTrace();
        }

        Collections.reverse(result);
        return result;
    }

    public static List<Date> getBetweenDates(Date start, Date end) {
        List<Date> result = new ArrayList();

        try {
            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(start);
            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(end);

            while (tempStart.before(tempEnd) || tempStart.equals(tempEnd)) {
                result.add(tempStart.getTime());
                tempStart.add(6, 1);
            }
        } catch (Exception var5) {
            var5.printStackTrace();
        }

        Collections.reverse(result);
        return result;
    }

    public static Date nextDate(Date newDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(newDate);
        calendar.add(5, 1);
        calendar.set(11, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        newDate = calendar.getTime();
        return newDate;
    }


    public static Date fillTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int hour = calendar.get(11);
        int min = calendar.get(12);
        int sec = calendar.get(13);
        if (hour == 0 && min == 0 && sec == 0) {
            calendar.set(11, 23);
            calendar.set(12, 59);
            calendar.set(13, 59);
            return calendar.getTime();
        } else {
            return date;
        }
    }

    public static Date endTime(Date date) {
        return fillTime(date);
    }

    public static Date beginTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(11, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        return calendar.getTime();
    }

    public static int getMonth(int year, int week) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1, year);
        int maxWeek = calendar.getActualMaximum(3);
        if (week > maxWeek) {
            return 12;
        } else {
            calendar.set(3, week);
            return calendar.get(2) + 1;
        }
    }


    public static Date fillTimeByMouth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(5, calendar.getMaximum(5));
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        return calendar.getTime();
    }

    public static String date2Str(Date date, String format) {
        return formatDate(date, format);
    }

    public static String date2Str(Date date) {
        return formatTime2(date);
    }

    public static Date str2Date(String strDate, String format) throws ParseException {
        Date date = null;
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        date = sdf.parse(strDate);
        return date;
    }

    public static Date str2Date(String strDate) throws ParseException {
        strDate = strDate.trim();
        SimpleDateFormat sdf = null;
        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }

        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}/(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])$")) {
            sdf = new SimpleDateFormat("yyyy/MM/dd");
        }

        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}/([1-9]|1[0-2])/([1-9]|[1-2][0-9]|3[0-1])$")) {
            sdf = new SimpleDateFormat("y/M/d");
        }

        if (RegularUtils.isMatched(strDate, "^(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$")) {
            sdf = new SimpleDateFormat("HH:mm:ss");
        }

        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }

        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        }

        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        }

        if (RegularUtils.isMatched(strDate, "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}Z$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        }

        if (null != sdf) {
            return sdf.parse(strDate);
        } else {
            throw new TimeMatchFormatException(String.format("[%s] can not matching right time format", strDate));
        }
    }

    public static Date str2DateUnmatch2Null(String strDate) {
        Date date = null;

        try {
            date = str2Date(strDate);
        } catch (Exception var3) {
            var3.printStackTrace();
        }

        return date;
    }


}
